﻿#pragma once
#include "LuaCommon.h"
#include <string>
#include <stdint.h>

namespace StackOps
{
	inline void Push(lua_State* L, bool value)				{	lua_pushboolean(L, value);  }
	inline void Push(lua_State* L, int8_t value)			{	lua_pushinteger(L, (lua_Integer)value);  }
	inline void Push(lua_State* L, uint8_t value)	    	{	lua_pushinteger(L, (lua_Integer)value);  }
	inline void Push(lua_State* L, int16_t value)			{	lua_pushinteger(L, (lua_Integer)value);  }
	inline void Push(lua_State* L, uint16_t value)			{	lua_pushinteger(L, (lua_Integer)value);  }
	inline void Push(lua_State* L, int32_t value)			{	lua_pushinteger(L, (lua_Integer)value);  }
	inline void Push(lua_State* L, uint32_t value)			{	lua_pushinteger(L, (lua_Integer)value);  }

	inline void Push(lua_State* L, double value)			{	lua_pushnumber(L, (lua_Number)value);  }
	inline void Push(lua_State* L, float value)				{	lua_pushnumber(L, (lua_Number)value);  }

#if LUA_VERSION_NUM > 502
	inline void Push(lua_State* L, int64_t value)			{	lua_pushinteger(L, value); }
	inline void Push(lua_State* L, uint64_t value)			{	lua_pushinteger(L, value); }
#else
	inline void Push(lua_State* L, int64_t value)			{	lua_pushnumber(L, value); }
	inline void Push(lua_State* L, uint64_t value)			{	lua_pushnumber(L, value); }
#endif

	inline void Push(lua_State* L, lua_CFunction value) { lua_pushcclosure(L, value, 0); }
	inline void Push(lua_State* L, const void* value) { lua_pushlightuserdata(L, (void*)value); }
	inline void Push(lua_State* L, const char* value) { lua_pushstring(L, value); }

	static void Push(lua_State* L, const wchar_t* utf16)
	{
		int utf8len=UTF16To8(NULL,0,(unsigned short*)utf16);
		StackBuffer<128> buf;
		buf.alloc(utf8len*sizeof(char));
		UTF16To8((char*)buf.buffer(), utf8len,(unsigned short*)utf16);
		lua_pushlstring(L,(char*)buf.buffer(),utf8len);
	}

	struct String {
		String(const char* s, size_t l) 
			:str(s),len(l)
		{
		}
		
		const char* str;
		size_t len;
	};

	inline void Push(lua_State* L, const char* value, size_t len) { lua_pushlstring(L, value, len); }
	inline void Push(lua_State* L, String s) { lua_pushlstring(L, s.str, s.len); }


	struct WString {
		WString(const wchar_t* s, size_t l)
			:str(s), len(l)
		{
		}

		const wchar_t* str;
		size_t len;
	};

	static void Push(lua_State* L, const wchar_t* utf16,size_t len)
	{
		int utf8len = UTF16To8(NULL,NULL,(unsigned short*)utf16, len);
		StackBuffer<128> buf;
		buf.alloc(utf8len * sizeof(char));
		UTF16To8((char*)buf.buffer(), utf8len,(unsigned short*)utf16);
		lua_pushlstring(L, (char*)buf.buffer(), utf8len);
	}

	inline void Push(lua_State* L, WString s) {
		Push(L, s.str, s.len);
	}

	inline void Push(lua_State* L, const std::string& value) { Push(L, value.c_str(), value.length()); }
	inline void Push(lua_State* L, const std::wstring& value) { Push(L, value.c_str(), value.length()); }

	inline void PushMulti(lua_State*) {}

	template<class T, class ...Args>
	inline void PushMulti(lua_State* L, T head, Args... rest) {
		Push(L, head);
		PushMulti(L,rest...);
	}

}